<!DOCTYPE html>
<html lang="zh-CN">

<head>
  <meta charset="UTF-8">
  <link rel="stylesheet" href="../css/github-markdown.min.css">
  <link rel="stylesheet" href="../css/github-gist.min.css">
  <link rel="stylesheet" href="../css/md.css">
</head>

<body>
  <div class="container">
    <!-- md 转 html 后 插入 -->
    <h1 id="koa">koa</h1>
<p>基于<code>NodeJS</code>平台的<code>web</code>开发框架</p>
<p>特点：轻量，语法新(<code>es6</code>)</p>
<h2 id="安装">安装</h2>
<p><code>koa-generator</code> 快速生成项目</p>
<pre><code><span class="hljs-regexp">//</span><span class="hljs-number">2</span>.x版本
npm i -g koa-generator</code></pre>
<pre><code><span class="hljs-regexp">//</span>生成项目
<span class="hljs-regexp">//</span>-e 增加ejs引擎支持
koa2 -e koa2-demo</code></pre>
<pre><code><span class="hljs-regexp">//</span>安装依赖
npm i</code></pre>
<pre><code><span class="hljs-regexp">//</span>项目启动
npm start</code></pre>
<pre><code><span class="hljs-regexp">//</span>测试是否启动成功
http:<span class="hljs-regexp">//</span>localhost:<span class="hljs-number">3000</span>/</code></pre>
<h2 id="ctx"><code>ctx</code></h2>
<p>该参数包含请求和响应的信息</p>
<pre><code><span class="hljs-comment">//测试</span>
<span class="hljs-comment">//src &gt; routes &gt; index.js</span>
router.get(<span class="hljs-string">&#x27;/asyncTest&#x27;</span>, <span class="hljs-keyword">async</span> (ctx) =&gt; {
  <span class="hljs-built_in">console</span>.log(<span class="hljs-string">&#x27;start&#x27;</span>, <span class="hljs-keyword">new</span> <span class="hljs-built_in">Date</span>().getTime());

  <span class="hljs-keyword">const</span> p = <span class="hljs-keyword">await</span> <span class="hljs-keyword">new</span> <span class="hljs-built_in">Promise</span>(<span class="hljs-function">(<span class="hljs-params">resolve, reject</span>) =&gt;</span> {
    <span class="hljs-built_in">setTimeout</span>(<span class="hljs-function">() =&gt;</span> {
      <span class="hljs-built_in">console</span>.log(<span class="hljs-string">&#x27;async test&#x27;</span>, <span class="hljs-keyword">new</span> <span class="hljs-built_in">Date</span>().getTime());
      resolve(<span class="hljs-string">&#x27;test&#x27;</span>);
    }, <span class="hljs-number">1000</span>)
  });

  ctx.body = {
    p
  }
});

<span class="hljs-comment">//打印</span>
{ <span class="hljs-string">&quot;p&quot;</span>: <span class="hljs-string">&quot;test&quot;</span> }</code></pre>
<h2 id="中间件">中间件</h2>
<blockquote>
<p>什么是洋葱模型？</p>
</blockquote>
<p><img src="https://gitee.com/kevinleeeee/blog-hexo-image-bed/raw/master/img//image-20210901022056267.png" alt="image-20210901022056267"></p>
<p>现在假想，你手里有一支牙签，横向穿过一个洋葱，是不是会层层穿透？从第一层进去、到第二层、第三次...然后到中间层后，再层层穿透的出，从第三层出、第二层、第一层...。其实我们的<code>koa2</code>中间件执行顺序也是这样的。抛开业务代码，用<code>koa2</code>官网的一个例子做实验</p>
<pre><code><span class="hljs-keyword">const</span> Koa = <span class="hljs-built_in">require</span>(<span class="hljs-string">&#x27;koa&#x27;</span>);
<span class="hljs-keyword">const</span> app = <span class="hljs-keyword">new</span> Koa();

<span class="hljs-comment">// logger</span>
app.use(<span class="hljs-keyword">async</span> (ctx, next) =&gt; {
  <span class="hljs-built_in">console</span>.log(<span class="hljs-string">&#x27;第一层洋葱 - 开始&#x27;</span>)
  <span class="hljs-keyword">await</span> next();
  <span class="hljs-keyword">const</span> rt = ctx.response.get(<span class="hljs-string">&#x27;X-Response-Time&#x27;</span>);
  <span class="hljs-built_in">console</span>.log(<span class="hljs-string">`<span class="hljs-subst">${ctx.method}</span> <span class="hljs-subst">${ctx.url}</span> - <span class="hljs-subst">${rt}</span>`</span>);
  <span class="hljs-built_in">console</span>.log(<span class="hljs-string">&#x27;第一层洋葱 - 结束&#x27;</span>)
});

<span class="hljs-comment">// x-response-time</span>
app.use(<span class="hljs-keyword">async</span> (ctx, next) =&gt; {
  <span class="hljs-built_in">console</span>.log(<span class="hljs-string">&#x27;第二层洋葱 - 开始&#x27;</span>)
  <span class="hljs-keyword">const</span> start = <span class="hljs-built_in">Date</span>.now();
  <span class="hljs-keyword">await</span> next();
  <span class="hljs-keyword">const</span> ms = <span class="hljs-built_in">Date</span>.now() - start;
  ctx.set(<span class="hljs-string">&#x27;X-Response-Time&#x27;</span>, <span class="hljs-string">`<span class="hljs-subst">${ms}</span>ms`</span>);
  <span class="hljs-built_in">console</span>.log(<span class="hljs-string">&#x27;第二层洋葱 - 结束&#x27;</span>)
});

<span class="hljs-comment">// response</span>
app.use(<span class="hljs-keyword">async</span> ctx =&gt; {
  <span class="hljs-built_in">console</span>.log(<span class="hljs-string">&#x27;第三层洋葱 - 开始&#x27;</span>)
  ctx.body = <span class="hljs-string">&#x27;Hello World&#x27;</span>;
  <span class="hljs-built_in">console</span>.log(<span class="hljs-string">&#x27;第三层洋葱 - 结束&#x27;</span>)
});

app.listen(<span class="hljs-number">8000</span>);</code></pre>
<p>打印结果是：</p>
<pre><code>第一层洋葱 - 开始
第二层洋葱 - 开始
第三层洋葱 - 开始
第三层洋葱 - 结束
第二层洋葱 - 结束
第一层洋葱 - 结束</code></pre>
<pre><code><span class="hljs-comment">//src &gt; app.js</span>
<span class="hljs-comment">//中间件引入</span>
<span class="hljs-keyword">const</span> views = <span class="hljs-keyword">require</span>(<span class="hljs-string">&#x27;koa-views&#x27;</span>)
<span class="hljs-keyword">const</span> json = <span class="hljs-keyword">require</span>(<span class="hljs-string">&#x27;koa-json&#x27;</span>)
<span class="hljs-keyword">const</span> onerror = <span class="hljs-keyword">require</span>(<span class="hljs-string">&#x27;koa-onerror&#x27;</span>)
<span class="hljs-keyword">const</span> bodyparser = <span class="hljs-keyword">require</span>(<span class="hljs-string">&#x27;koa-bodyparser&#x27;</span>)

<span class="hljs-comment">//中间件注册</span>
app.<span class="hljs-keyword">use</span>(bodyparser({
  enableTypes:[<span class="hljs-string">&#x27;json&#x27;</span>, <span class="hljs-string">&#x27;form&#x27;</span>, <span class="hljs-string">&#x27;text&#x27;</span>]
}))
app.<span class="hljs-keyword">use</span>(json())
app.<span class="hljs-keyword">use</span>(logger())
app.<span class="hljs-keyword">use</span>(<span class="hljs-keyword">require</span>(<span class="hljs-string">&#x27;koa-static&#x27;</span>)(__dirname + <span class="hljs-string">&#x27;/public&#x27;</span>))

app.<span class="hljs-keyword">use</span>(views(__dirname + <span class="hljs-string">&#x27;/views&#x27;</span>, {
  extension: <span class="hljs-string">&#x27;ejs&#x27;</span>
}))</code></pre>
<p>手写中间件</p>
<pre><code><span class="hljs-comment">//src &gt; app.js</span>
<span class="hljs-comment">//引入和注册</span>
<span class="hljs-keyword">const</span> midtest = <span class="hljs-keyword">require</span>(<span class="hljs-string">&#x27;./middleware/koa-mid&#x27;</span>);
app.<span class="hljs-keyword">use</span>(midtest());</code></pre>
<pre><code><span class="hljs-comment">//src &gt; middleware &gt; koa-mid.js</span>
<span class="hljs-comment">//中间件会打印两次</span>
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">mid</span>(<span class="hljs-params">ctx</span>) </span>{
  <span class="hljs-comment">//打印页面路径</span>
  <span class="hljs-built_in">console</span>.log(<span class="hljs-string">&#x27;midtest&#x27;</span>, ctx.path);
}

<span class="hljs-built_in">module</span>.exports = <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">return</span> <span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">ctx, next</span>) </span>{
    mid(ctx);
    <span class="hljs-keyword">await</span> next();
  }
}</code></pre>
<h2 id="路由">路由</h2>
<pre><code><span class="hljs-regexp">//</span>src &gt; routes &gt; users.js
<span class="hljs-regexp">//</span>前缀 prefix()
router.prefix(<span class="hljs-string">&#x27;/users&#x27;</span>)

router.get(<span class="hljs-string">&#x27;/&#x27;</span>, <span class="hljs-keyword">function</span> (ctx, <span class="hljs-keyword">next</span>) {
  ctx.body = <span class="hljs-string">&#x27;this is a users response!&#x27;</span>
})

<span class="hljs-regexp">//</span>访问方法：
<span class="hljs-regexp">//</span>http:<span class="hljs-regexp">//</span>localhost:<span class="hljs-number">3000</span><span class="hljs-regexp">/users/</span></code></pre>
<h2 id="cookiesession">cookie/session</h2>
<pre><code>router.<span class="hljs-keyword">get</span>(<span class="hljs-string">&#x27;/&#x27;</span>, <span class="hljs-keyword">async</span> (ctx, next) =&gt; {
  ctx.cookies.<span class="hljs-keyword">set</span>(<span class="hljs-string">&#x27;testid&#x27;</span>, Math.random());

  <span class="hljs-keyword">await</span> ctx.render(<span class="hljs-string">&#x27;index&#x27;</span>, {
    title: <span class="hljs-string">&#x27;Hello Koa 2!&#x27;</span>
  })
})

<span class="hljs-comment">//浏览器application里cookies显示字段name和值</span></code></pre>
<h2 id="案例">案例</h2>
<p>美团网页版项目</p>
<p>技术：<code>vue + koa2 + ElementUI + Redis + MongoDB + SSR + NuxtJS</code></p>
<p>项目创建</p>
<pre><code><span class="hljs-string">npx </span><span class="hljs-built_in">create-nuxt-app@2</span> <span class="hljs-string">meituan-demo</span></code></pre>
<p>项目选择配置</p>
<pre><code><span class="hljs-symbol">UI:</span> element
<span class="hljs-symbol">server:</span> koa
<span class="hljs-symbol">modules:</span> axios
<span class="hljs-symbol">render:</span> universal(ssr)</code></pre>
<p>启动项目</p>
<pre><code>npm run dev

<span class="hljs-regexp">//</span>访问
http:<span class="hljs-regexp">//</span>localhost:<span class="hljs-number">3000</span>/</code></pre>
<p>目录结构</p>
<pre><code>├─nuxt.config.js               -配置文件
├─package-lock.json
├─package.json
├─README.md
├─store                        -管理vuex状态
├─static                       -管理图标(非必须)
<span class="hljs-string">|   ├─favicon.ico</span>
├─server                       -管理服务端代码
<span class="hljs-string">|   └index.js</span>
├─plugins                      -管理插件
<span class="hljs-string">|    ├─element-ui.js</span>
├─pages
<span class="hljs-string">|   ├─about.vue</span>
<span class="hljs-string">|   ├─index.vue</span>
├─middleware                   -管理中间件
├─layouts                      -管理默认模板
<span class="hljs-string">|    ├─default.vue</span>
├─components                   -管理组件
<span class="hljs-string">|     ├─Logo.vue</span>
├─assets                       -管理静态资源文件
<span class="hljs-string">|   ├─css</span></code></pre>
<p>创建.babelrc 配置文件</p>
<pre><code><span class="hljs-comment">//配置babel</span>
{
  <span class="hljs-attr">&quot;presets&quot;</span>: [<span class="hljs-string">&quot;es2015&quot;</span>]
}</code></pre>
<p>安装<code>babel</code>处理<code>es6</code>语法</p>
<pre><code><span class="hljs-attribute">npm</span> i -D babel-preset-es<span class="hljs-number">2015</span>@<span class="hljs-number">6</span>.<span class="hljs-number">24</span>.<span class="hljs-number">1</span>
<span class="hljs-attribute">npm</span> i -D babel-cli@<span class="hljs-number">6</span>.<span class="hljs-number">26</span>.<span class="hljs-number">0</span>
<span class="hljs-attribute">npm</span> i -D babel-core@<span class="hljs-number">6</span>.<span class="hljs-number">26</span>.<span class="hljs-number">3</span></code></pre>
<p>安装<code>scss</code>处理器</p>
<pre><code>npm i -D sass-<span class="hljs-symbol">loader@</span><span class="hljs-number">7.1</span><span class="hljs-number">.0</span>
npm i -D node-<span class="hljs-symbol">sass@</span><span class="hljs-number">4.11</span><span class="hljs-number">.0</span></code></pre>
<p>配置<code>nuxt.config.js</code></p>
<pre><code>/<span class="hljs-regexp">/引入初始化css文件
css: [
  &#x27;element-ui/lib</span><span class="hljs-regexp">/theme-chalk/reset</span>.css<span class="hljs-string">&#x27;,
  &#x27;</span>element-ui/<span class="hljs-class"><span class="hljs-keyword">lib</span>/<span class="hljs-title">theme</span>-<span class="hljs-title">chalk</span>/<span class="hljs-title">index</span>.<span class="hljs-title">css</span>&#x27;，</span>
  <span class="hljs-string">&#x27;@/assets/css/main.css&#x27;</span>
],</code></pre>
<p>编写后台接口</p>
<pre><code><span class="hljs-regexp">//</span>server目录新建dbs数据库目录
<span class="hljs-regexp">//</span>dbs数据库目录里创建models模型目录
<span class="hljs-regexp">//</span>server &gt; dbs &gt; models模型目录创建users.js文件
<span class="hljs-regexp">//</span>server &gt; dbs目录下创建config.js配置文件(数据库相关信息)
<span class="hljs-regexp">//</span>server目录新建interface接口目录
<span class="hljs-regexp">//i</span>nterface目录新建utils工具目录
<span class="hljs-regexp">//</span>server &gt; interface新建users.js文件
<span class="hljs-regexp">//</span>server &gt; interface &gt; utils新建axios.js文件(封装全局使用axios)
<span class="hljs-regexp">//</span>server &gt; interface &gt; utils新建passport.js文件(验证相关权限)</code></pre>
<pre><code><span class="hljs-regexp">//</span>POP3邮箱开启授权码
adgkisdouidsbhda
<span class="hljs-regexp">//</span>IMAP/SMTP服务授权码
pthqrkenxqzdbhji</code></pre>
<pre><code><span class="hljs-comment">//server &gt; dbs &gt; config.js</span>
<span class="hljs-comment">//数据库相关信息</span>
<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> {
  <span class="hljs-attr">dbs</span>: <span class="hljs-string">&#x27;mongodb://127.0.0.1:27017/meituan/users&#x27;</span>,
  <span class="hljs-attr">redis</span>: {
    <span class="hljs-comment">//主机地址，只读</span>
    <span class="hljs-keyword">get</span> <span class="hljs-title">host</span>() {
      <span class="hljs-keyword">return</span> <span class="hljs-string">&#x27;127.0.0.1&#x27;</span>;
    },
    <span class="hljs-keyword">get</span> <span class="hljs-title">port</span>() {
      <span class="hljs-comment">//端口号</span>
      <span class="hljs-keyword">return</span> <span class="hljs-number">6379</span>;
    }
  },
  <span class="hljs-comment">//腾讯提供的服务 邮箱</span>
  <span class="hljs-attr">smtp</span>: {
    <span class="hljs-keyword">get</span> <span class="hljs-title">host</span>() {
      <span class="hljs-keyword">return</span> <span class="hljs-string">&#x27;smtp.qq.com&#x27;</span>
    },
    <span class="hljs-keyword">get</span> <span class="hljs-title">user</span>() {
      <span class="hljs-keyword">return</span> <span class="hljs-string">&#x27;273122188@qq.com&#x27;</span>
    },
    <span class="hljs-keyword">get</span> <span class="hljs-title">pass</span>() {
      <span class="hljs-keyword">return</span> <span class="hljs-string">&#x27;保密字符&#x27;</span>;
    },
    <span class="hljs-keyword">get</span> <span class="hljs-title">code</span>() {
      <span class="hljs-keyword">return</span> <span class="hljs-function">() =&gt;</span> {
        <span class="hljs-comment">//返回随机16进制字符</span>
        <span class="hljs-keyword">return</span> <span class="hljs-built_in">Math</span>.random().toString(<span class="hljs-number">16</span>).slice(<span class="hljs-number">2</span>, <span class="hljs-number">6</span>).toUpperCase();
      }
    },
    <span class="hljs-comment">//过期时间</span>
    <span class="hljs-keyword">get</span> <span class="hljs-title">expire</span>() {
      <span class="hljs-keyword">return</span> <span class="hljs-function">() =&gt;</span> {
        <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> <span class="hljs-built_in">Date</span>().getTime() + <span class="hljs-number">60</span> * <span class="hljs-number">1000</span>
      }
    }
  }
}</code></pre>
<blockquote>
<p>关于<code>nodemailer</code>：</p>
<p><a href="https://nodemailer.com/about/">https://nodemailer.com/about/</a></p>
<p>是一个用于 Node.js 应用程序的模块(中间件)，它轻松地发送电子邮件</p>
</blockquote>
<pre><code><span class="hljs-comment">//安装nodemailer</span>
npm i -S <span class="hljs-symbol">nodemailer@</span><span class="hljs-number">6.1</span><span class="hljs-number">.0</span>

<span class="hljs-comment">//引入</span>
<span class="hljs-keyword">import</span> nodeMailer <span class="hljs-keyword">from</span> <span class="hljs-string">&#x27;nodemailer&#x27;</span>;

<span class="hljs-comment">//接口内部使用</span>
let transporter = nodeMailer.createTransport({
  host: EmailConfig.smtp.host,
  port: <span class="hljs-number">587</span>,
  secure: <span class="hljs-literal">false</span>,
  auth: {
    user: EmailConfig.smtp.user,
    pass: EmailConfig.smtp.pass,
  },
});</code></pre>
<pre><code><span class="hljs-comment">//安装依赖</span>
npm i -S koa-<span class="hljs-symbol">redis@</span><span class="hljs-number">3.1</span><span class="hljs-number">.3</span>
npm i -S koa-<span class="hljs-symbol">router@</span><span class="hljs-number">7.4</span><span class="hljs-number">.0</span>
npm i -S <span class="hljs-symbol">axios@</span><span class="hljs-number">0.18</span><span class="hljs-number">.0</span>
npm i -S koa-generic-<span class="hljs-symbol">session@</span><span class="hljs-number">2.0</span><span class="hljs-number">.1</span>
npm i -S koa-<span class="hljs-symbol">bodyparser@</span><span class="hljs-number">4.2</span><span class="hljs-number">.1</span>
npm i -S koa-<span class="hljs-symbol">json@</span><span class="hljs-number">2.0</span><span class="hljs-number">.2</span>
npm i -S koa-<span class="hljs-symbol">redis@</span><span class="hljs-number">3.1</span><span class="hljs-number">.2</span>
npm i -S <span class="hljs-symbol">mongoose@</span><span class="hljs-number">5.5</span><span class="hljs-number">.2</span>
npm i -S koa-<span class="hljs-symbol">passport@</span><span class="hljs-number">4.1</span><span class="hljs-number">.1</span>
npm i -S passport-<span class="hljs-symbol">local@</span><span class="hljs-number">1.0</span><span class="hljs-number">.0</span></code></pre>
<pre><code><span class="hljs-regexp">//</span>编写后台接口
<span class="hljs-regexp">//</span>server &gt; interface &gt; users.js</code></pre>
<blockquote>
<p>关于<code>PassportJs</code></p>
<p><a href="http://www.passportjs.org/docs/">http://www.passportjs.org/docs/</a></p>
<p>Node.js 的身份验证中间件。Passport 非常灵活和模块化，可以不显眼地插入任何 基于 Express 的 Web 应用程序。一套全面策略支持认证使用的用户名和密码</p>
</blockquote>
<blockquote>
<p>关于<code>CryptoJS</code></p>
<p>密码加密的前端库</p>
</blockquote>
<pre><code><span class="hljs-comment">//安装</span>
npm i -S crypto-js@<span class="hljs-number">3.1</span>.<span class="hljs-number">9</span>-<span class="hljs-number">1</span>

<span class="hljs-comment">//引入</span>
import CryptoJS from &#x27;crypto-js&#x27;;

<span class="hljs-comment">//使用</span>
this.$axios.pist(<span class="hljs-string">&quot;/users/signup&quot;</span>, {
  username: encode<span class="hljs-constructor">URIComponent(<span class="hljs-params">this</span>.<span class="hljs-params">ruleForm</span>.<span class="hljs-params">name</span>)</span>,
  password: CryptoJS.<span class="hljs-constructor">MD5(<span class="hljs-params">this</span>.<span class="hljs-params">ruleForm</span>.<span class="hljs-params">pwd</span>)</span>.<span class="hljs-keyword">to</span><span class="hljs-constructor">String()</span>,
});</code></pre>
<p>由于后端数据接口失效，请求功能不完善。</p>
<p>源码地址：<a href="https://gitee.com/kevinleeeee/meituan-web">https://gitee.com/kevinleeeee/meituan-web</a></p>
<h1 id="koa2">koa2</h1>
<h2 id="介绍">介绍</h2>
<p><code>web</code>框架，<code>express</code>幕后打造</p>
<p><strong>特点:</strong></p>
<p>更小，更灵活，利用<code>async</code>函数丢掉回调函数，增强错误处理，没有中间件，书写优雅</p>
<p><strong>区别：</strong></p>
<ul>
<li><code>koa1</code>:<code> generator/yeild</code></li>
<li><code>koa2</code>: <code>async/await </code>, 小而精, 且提供执行期上下文<code>ctx</code></li>
<li><code>express</code>: 回调函数，大而全, 不提供执行期上下文<code>ctx</code>，手动处理</li>
</ul>
<h2 id="搭建">搭建</h2>
<pre><code><span class="hljs-regexp">//</span>安装koa生成器依赖
npm i -g koa-generator

<span class="hljs-regexp">//</span>创建项目
koa2 xiaomi_mobile_pro

<span class="hljs-regexp">//</span>安装依赖
npm install

<span class="hljs-regexp">//</span>运行
npm run dev

<span class="hljs-regexp">//</span>访问
http:<span class="hljs-regexp">//</span>localhost:<span class="hljs-number">3000</span>/</code></pre>
<h2 id="脚本">脚本</h2>
<p><code>koa2</code>项目的默认脚本命令</p>
<pre><code><span class="hljs-string">&quot;scripts&quot;</span>: {
  <span class="hljs-string">&quot;start&quot;</span>: <span class="hljs-string">&quot;node bin/www&quot;</span>, <span class="hljs-regexp">//</span>默认启动node
  <span class="hljs-string">&quot;dev&quot;</span>: <span class="hljs-string">&quot;./node_modules/.bin/nodemon bin/www&quot;</span>, <span class="hljs-regexp">//</span>启动nodemon(log)
  <span class="hljs-string">&quot;prd&quot;</span>: <span class="hljs-string">&quot;pm2 start bin/www&quot;</span>, <span class="hljs-regexp">//</span>通过pm2管理进程
  <span class="hljs-string">&quot;test&quot;</span>: <span class="hljs-string">&quot;echo \&quot;Error: no test specified\&quot; &amp;&amp; exit 1&quot;</span>, <span class="hljs-regexp">//</span>测试
}</code></pre>
<h2 id="打包">打包</h2>
<p><strong><em>问题：如何结合前端的代码，样式，脚本，图片进行打包处理？</em></strong></p>
<p>通过<code>webpack</code>构建工具进行打包</p>
<p><strong><em>问题：如何实现边开发边打包，页面实时渲染？</em></strong></p>
<p>通过<code>koa</code>服务器，和<code>webpack-dev-server</code>服务器协调运作，前者用来解析网站，后者用来打包</p>
<p><strong><code>koa</code>项目改造：</strong></p>
<p><img src="https://gitee.com/kevinleeeee/blog-hexo-image-bed/raw/master/img//image-20220312054615622.png" alt="image-20220312054615622"></p>
<ul>
<li>打包后目录为：<code>/public</code>目录(静态样式，脚本，图片)</li>
</ul>
<p><strong>配置<code>webpack</code>：</strong></p>
<p><code>dev</code>脚本命令时，使其自动打包，并显示代码效果，实现边开发边打包，页面实时渲染</p>
<pre><code><span class="hljs-keyword">const</span> path = <span class="hljs-built_in">require</span>(<span class="hljs-string">&#x27;path&#x27;</span>),
      <span class="hljs-comment">//压缩混淆JS</span>
      Uglify = <span class="hljs-built_in">require</span>(<span class="hljs-string">&#x27;uglifyjs-webpack-plugin&#x27;</span>),
      <span class="hljs-comment">//处理CSS前缀</span>
      Autoprefixer = <span class="hljs-built_in">require</span>(<span class="hljs-string">&#x27;autoprefixer&#x27;</span>),
      <span class="hljs-comment">//将CSS提取为独立的文件</span>
      MiniCssExtractPlugin = <span class="hljs-built_in">require</span>(<span class="hljs-string">&#x27;mini-css-extract-plugin&#x27;</span>),
      <span class="hljs-comment">//用于优化或者压缩CSS资源</span>
      OptimizeCssAssetsPlugin = <span class="hljs-built_in">require</span>(<span class="hljs-string">&#x27;optimize-css-assets-webpack-plugin&#x27;</span>);

<span class="hljs-keyword">const</span> config = {
  mode: <span class="hljs-string">&#x27;production&#x27;</span>,
  entry: {
      index: path.resolve(__dirname, <span class="hljs-string">&#x27;./src/js/index.js&#x27;</span>),
    list: path.resolve(__dirname, <span class="hljs-string">&#x27;./src/js/list.js&#x27;</span>),
  },
  output: {
      path: path.resolve(__dirname + <span class="hljs-string">&#x27;/public&#x27;</span>),
      filename: <span class="hljs-string">&#x27;js/[name].js&#x27;</span>,
    publicPath: <span class="hljs-string">&#x27;/&#x27;</span>
  },
  <span class="hljs-keyword">module</span>: {
      rules: rules: [
      {
        test: <span class="hljs-regexp">/\.js$/</span>,
        loader: <span class="hljs-string">&#x27;babel-loader&#x27;</span>,
        exclude: [path.resolve(__dirname, <span class="hljs-string">&#x27;node_modules&#x27;</span>)],
      },
      {
        test: <span class="hljs-regexp">/\.tpl$/</span>,
        loader: <span class="hljs-string">&#x27;ejs-loader&#x27;</span>,
      },
      {
        test: <span class="hljs-regexp">/\.scss$/</span>,
        use: [
          {
            loader: MiniCssExtractPlugin.loader,
            options: {
              hmr: process.env.NODE_ENV === <span class="hljs-string">&#x27;development&#x27;</span>,
            },
          },
          <span class="hljs-string">&#x27;css-loader&#x27;</span>,
          {
            loader: <span class="hljs-string">&#x27;postcss-loader&#x27;</span>,
            options: {
              plugin() {
                <span class="hljs-keyword">return</span> [autoprefixer(<span class="hljs-string">&#x27;last 5 versions&#x27;</span>)];
              },
            },
          },
          <span class="hljs-string">&#x27;sass-loader&#x27;</span>,
        ],
      },
      {
        test: <span class="hljs-regexp">/\.css$/</span>,
        use: [
          {
            loader: MiniCssExtractPlugin.loader,
            options: {
              hmr: process.env.NODE_ENV === <span class="hljs-string">&#x27;development&#x27;</span>,
            },
          },
          <span class="hljs-string">&#x27;css-loader&#x27;</span>,
          {
            loader: <span class="hljs-string">&#x27;postcss-loader&#x27;</span>,
            options: {
              plugin() {
                <span class="hljs-keyword">return</span> [autoprefixer(<span class="hljs-string">&#x27;last 5 versions&#x27;</span>)];
              },
            },
          },
        ],
      },
      {
        test: <span class="hljs-regexp">/\.(png|jpg|jpeg|gif|ico)$/i</span>,
        loader: [<span class="hljs-string">&#x27;url-loader?limit=2048&amp;name=img/[name]-[hash:16].[ext]&#x27;</span>],
      },
      {
        test: <span class="hljs-regexp">/\.(woff2?|eot|ttf|oft|svg)(\?.*)?$/i</span>,
        loader: [<span class="hljs-string">&#x27;url-loader?name=fonts/[name].[ext]&#x27;</span>],
      },
    ]
  },

  plugins: [
    <span class="hljs-keyword">new</span> Uglify(),
    <span class="hljs-keyword">new</span> OptimizeCssAssetsPlugin({}),
    <span class="hljs-keyword">new</span> MiniCssExtractPlugin({
      filename: <span class="hljs-string">&#x27;css/[name].css&#x27;</span>
    })
  ],

  devServer: {
      watchOptions: {
        ignoreed: <span class="hljs-regexp">/node_modules/</span>
      },
      host: <span class="hljs-string">&#x27;localhost&#x27;</span>,
      port: <span class="hljs-number">3300</span>
  }
}

<span class="hljs-built_in">module</span>.<span class="hljs-built_in">exports</span> = config;</code></pre>
<p><strong>安装<code>webpack</code>相关的依赖：</strong></p>
<pre><code><span class="hljs-string">&quot;autoprefixer&quot;</span>: <span class="hljs-string">&quot;^9.5.1&quot;</span>,
<span class="hljs-string">&quot;babel-core&quot;</span>: <span class="hljs-string">&quot;^6.26.3&quot;</span>,
<span class="hljs-string">&quot;babel-loader&quot;</span>: <span class="hljs-string">&quot;^7.1.5&quot;</span>,
<span class="hljs-string">&quot;babel-plugin-transform-decorators&quot;</span>: <span class="hljs-string">&quot;^6.24.1&quot;</span>,
<span class="hljs-string">&quot;babel-plugin-transform-decorators-legacy&quot;</span>: <span class="hljs-string">&quot;^1.3.5&quot;</span>,
<span class="hljs-string">&quot;babel-plugin-transform-runtime&quot;</span>: <span class="hljs-string">&quot;^6.23.0&quot;</span>,
<span class="hljs-string">&quot;babel-preset-env&quot;</span>: <span class="hljs-string">&quot;^1.7.0&quot;</span>,
<span class="hljs-string">&quot;babel-preset-latest&quot;</span>: <span class="hljs-string">&quot;^6.24.1&quot;</span>,
<span class="hljs-string">&quot;css-loader&quot;</span>: <span class="hljs-string">&quot;^2.1.1&quot;</span>,
<span class="hljs-string">&quot;ejs-loader&quot;</span>: <span class="hljs-string">&quot;^0.3.5&quot;</span>,
<span class="hljs-string">&quot;file-loader&quot;</span>: <span class="hljs-string">&quot;^3.0.1&quot;</span>,
<span class="hljs-string">&quot;html-webpack-plugin&quot;</span>: <span class="hljs-string">&quot;^3.2.0&quot;</span>,
<span class="hljs-string">&quot;mini-css-extract-plugin&quot;</span>: <span class="hljs-string">&quot;^0.8.0&quot;</span>,
<span class="hljs-string">&quot;node-sass&quot;</span>: <span class="hljs-string">&quot;^4.11.0&quot;</span>,
<span class="hljs-string">&quot;nodemon&quot;</span>: <span class="hljs-string">&quot;^1.19.1&quot;</span>,
<span class="hljs-string">&quot;optimize-css-assets-webpack-plugin&quot;</span>: <span class="hljs-string">&quot;^5.0.3&quot;</span>,
<span class="hljs-string">&quot;postcss-loader&quot;</span>: <span class="hljs-string">&quot;^3.0.0&quot;</span>,
<span class="hljs-string">&quot;sass-loader&quot;</span>: <span class="hljs-string">&quot;^7.1.0&quot;</span>,
<span class="hljs-string">&quot;style-loader&quot;</span>: <span class="hljs-string">&quot;^0.23.1&quot;</span>,
<span class="hljs-string">&quot;uglifyjs-webpack-plugin&quot;</span>: <span class="hljs-string">&quot;^2.1.2&quot;</span>,
<span class="hljs-string">&quot;url-loader&quot;</span>: <span class="hljs-string">&quot;^1.1.2&quot;</span>,
<span class="hljs-string">&quot;webpack&quot;</span>: <span class="hljs-string">&quot;^4.30.0&quot;</span>,
<span class="hljs-string">&quot;webpack-cli&quot;</span>: <span class="hljs-string">&quot;^3.3.7&quot;</span>,
<span class="hljs-string">&quot;webpack-dev-server&quot;</span>: <span class="hljs-string">&quot;^3.7.2&quot;</span></code></pre>
<p><code>node-fetch@2.6.0</code>：向纯后端再次发起数据请求功能</p>
<blockquote>
<p><strong>关于<code>html-webpack-plugin</code>：</strong></p>
<p>在<code>SSR</code>渲染的项目中，并不需要使用<code>html-webpack-plugin</code>，它是在生产环境下做的，因为<code>koa2</code>环境下，页面是<code>EJS</code>页面显示的，每次线上都会解析<code>EJS</code>模板形成最终的<code>HTML</code>返回给前端，而<code>webpack</code>打包出来的是静态资源</p>
</blockquote>
<p><strong>配置<code>.babelrc</code>文件：</strong></p>
<pre><code>{
    <span class="hljs-attr">&quot;presets&quot;</span>: [<span class="hljs-string">&quot;env&quot;</span>],
    <span class="hljs-attr">&quot;plugins&quot;</span>: [
    <span class="hljs-comment">//装饰器</span>
    <span class="hljs-string">&quot;transform-decorators-legacy&quot;</span>,
    <span class="hljs-comment">//async await迭代器适用es7 es8写法</span>
    <span class="hljs-string">&quot;babel-plugin-transform-runtime&quot;</span>
    ]
}</code></pre>
<p><strong>配置脚本命令：</strong></p>
<pre><code><span class="hljs-string">&quot;scripts&quot;</span>: {
  <span class="hljs-string">&quot;start&quot;</span>: <span class="hljs-string">&quot;node bin/www&quot;</span>, <span class="hljs-regexp">//</span>默认启动node
  <span class="hljs-string">&quot;dev&quot;</span>: <span class="hljs-string">&quot;./node_modules/.bin/nodemon bin/www&quot;</span>, <span class="hljs-regexp">//</span>启动nodemon(log)
  <span class="hljs-string">&quot;prd&quot;</span>: <span class="hljs-string">&quot;pm2 start bin/www&quot;</span>, <span class="hljs-regexp">//</span>通过pm2管理进程
   <span class="hljs-regexp">//</span>同时也要启动webpack服务器
  <span class="hljs-string">&quot;webpack&quot;</span>: <span class="hljs-string">&quot;webpack-dev-server --host localhost --content-base app/public/ --hot --config webpack.config.js --progress --display-modules --colors --display-reasons&quot;</span>,
  <span class="hljs-string">&quot;build&quot;</span>:<span class="hljs-string">&quot;webpack --config webpack.config.js&quot;</span>
}</code></pre>
<p><strong>关键引入：</strong></p>
<p>在<code>koa</code>的<code>view</code>模板<code>html</code>文件里引入<code>webpack-dev-server</code>启动的服务器地址</p>
<pre><code><span class="hljs-tag">&lt;<span class="hljs-name">script</span> <span class="hljs-attr">src</span>=<span class="hljs-string">&quot;http://localhost:3400/js/index.js&quot;</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span></code></pre>
<p><strong>分别同时启动服务器：</strong></p>
<pre><code><span class="hljs-regexp">//</span>koa2
npm run dev

<span class="hljs-regexp">//</span>webpack 该命令打包css,js后缓存到/piblic目录 需要在index.html引入
npm run webpack

<span class="hljs-regexp">//</span>此时可以在koa2项目中, view页面正常显示, 并且可以看到实时更新逻辑代码</code></pre>
<p><strong>源码地址：</strong></p>
<p>这是一个基于<code>koa2</code>和<code>webpack</code>热更新搭建好的脚手架</p>
<p><a href="https://gitee.com/kevinleeeee/webpack-koa2-cli">https://gitee.com/kevinleeeee/webpack-koa2-cli</a></p>
<h2 id="案例-1">案例</h2>
<p><strong><u>案例：小米网页官网前后端案例</u></strong></p>
<p><code>koa2</code>+<code>ejs </code>+ <code>nodejs </code>+ <code>webpack</code></p>
<p><strong>项目结构：</strong></p>
<pre><code>├─app.js               <span class="hljs-comment">--- 应用入口文件</span>
├─<span class="hljs-built_in">package</span>.json
├─views                <span class="hljs-comment">--- 后端页面渲染模板</span>
|   ├─<span class="hljs-built_in">error</span>.pug
|   ├─index.pug
|   └layout.pug
├─routes               <span class="hljs-comment">--- 后端路由系统</span>
|   ├─index.js
|   └users.js
├─public               <span class="hljs-comment">--- 前端静态文件</span>
                       /打包后的静态样式文件，脚本，图片
|   ├─stylesheets
|   |      └style.css
|   ├─javascripts
|   ├─images
├─bin                  <span class="hljs-comment">--- 系统必备执行文件</span>
|  └www
├─<span class="hljs-built_in">config</span>               <span class="hljs-comment">--- 开发配置文件</span>
├─controllers          <span class="hljs-comment">--- 控制器，类方式管理路由的回调</span>
├─lib                  <span class="hljs-comment">--- 自定义库文件</span>
├─middlewares          <span class="hljs-comment">--- 自定义中间件</span>
├─models               <span class="hljs-comment">--- 数据请求模型</span>
├─src                  <span class="hljs-comment">--- 前端相应文件夹</span>
├─views                <span class="hljs-comment">--- 后端页面渲染模板</span>
├─.babelrc             <span class="hljs-comment">--- babel兼容性配置文件</span>
├─deploy.yaml          <span class="hljs-comment">--- pm2线上部署与发布脚本</span>
├─webpack.<span class="hljs-built_in">config</span>.js    <span class="hljs-comment">--- 打包配置文件</span></code></pre>
<p><strong>前后端渲染过程：</strong></p>
<p>前端 -&gt; <code>Node</code>层(请求数据/组装<code>HTML</code>/<code>model</code>层) -&gt; 纯后端(数据接口)</p>
<p><strong>源码地址：</strong> <a href="https://gitee.com/kevinleeeee/xiaomi-web-koa2-project">https://gitee.com/kevinleeeee/xiaomi-web-koa2-project</a></p>
<h1 id="ejs">EJS</h1>
<p><strong><code>ejs</code>语法：</strong></p>
<pre><code><span class="xml">//html标签作为变量
<span class="hljs-tag">&lt;<span class="hljs-name">%=</span> <span class="hljs-attr">title</span> =<span class="hljs-string">%</span>&gt;</span>

//JavaScript语句
<span class="hljs-tag">&lt;<span class="hljs-name">%</span> <span class="hljs-attr">for</span>(<span class="hljs-attr">var</span> <span class="hljs-attr">i</span> = <span class="hljs-string">0;</span> <span class="hljs-attr">i</span> &lt; <span class="hljs-attr">arr.length</span>; <span class="hljs-attr">i</span>++){
  <span class="hljs-attr">var</span> <span class="hljs-attr">item</span> = <span class="hljs-string">arr[i];</span>
%&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">h1</span>&gt;</span><span class="hljs-tag">&lt;<span class="hljs-name">%=</span> <span class="hljs-attr">item.name</span> %&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">%</span> } %&gt;</span>

//引入ejs文件时, 且可以传入参数
<span class="hljs-tag">&lt;<span class="hljs-name">%-</span> <span class="hljs-attr">include</span>(&#x27;<span class="hljs-attr">xxx.ejs</span>&#x27;, <span class="hljs-attr">params</span>) %&gt;</span></span></code></pre>
<h1 id="ssr">SSR</h1>
<p><strong><u>案例：腾讯课堂官网网页版</u></strong></p>
<p>这是一个基于爬虫数据 制作的前端页面</p>
<p><strong>功能：</strong></p>
<ul>
<li>首页搜索栏搜索课程</li>
<li>首页轮播图</li>
<li>首页课程老师学生列表渲染</li>
<li>首页底部雪碧图链接</li>
<li>列表页 tab 栏切换渲染列表</li>
<li>错误页渲染</li>
</ul>
<p><strong>技术：</strong></p>
<ul>
<li>原生<code>JS</code></li>
<li><code>webpack</code>工程化</li>
<li><code>koa2</code></li>
<li><code>SSR</code>服务端渲染</li>
<li><code>EJS</code>模板系统</li>
<li>前端数据库：<code>MySQL</code></li>
<li>后端</li>
</ul>
<p><strong>案例展示图：</strong></p>
<p><img src="https://gitee.com/kevinleeeee/blog-hexo-image-bed/raw/master/img//image-20220312021009957.png" alt="image-20220312021009957"></p>
<p><img src="https://gitee.com/kevinleeeee/blog-hexo-image-bed/raw/master/img//image-20220312021030313.png" alt="image-20220312021030313"></p>
<p><img src="https://gitee.com/kevinleeeee/blog-hexo-image-bed/raw/master/img//image-20220312020639395.png" alt="image-20220312020639395"></p>
<p><img src="https://gitee.com/kevinleeeee/blog-hexo-image-bed/raw/master/img//image-20220312021058972.png" alt="image-20220312021058972"></p>
<p><strong>项目启动注意：</strong></p>
<pre><code><span class="hljs-comment">//1.先打包</span>
npm <span class="hljs-built_in">run</span> build

<span class="hljs-comment">//2.再测试</span>
npm <span class="hljs-built_in">run</span> dev</code></pre>
<p><strong>项目目录：</strong></p>
<pre><code>├─.babelrc
├─app.js - 后端服务器程序
├─package.json
├─webpack.config.js
├─src
|<span class="hljs-string">  ├─views - 模板ejs文件/引入子模板/传参
</span>|<span class="hljs-string">  </span>|<span class="hljs-string">   ├─error.ejs - 入口文件/错误页
</span>|<span class="hljs-string">  </span>|<span class="hljs-string">   ├─index.ejs - 入口文件
</span>|<span class="hljs-string">  </span>|<span class="hljs-string">   ├─list.ejs - 入口文件/列表页
</span>|<span class="hljs-string">  </span>|<span class="hljs-string">   ├─templates - 被引入的模板
</span>|<span class="hljs-string">  </span>|<span class="hljs-string">   </span>|<span class="hljs-string">     ├─list
</span>|<span class="hljs-string">  </span>|<span class="hljs-string">   </span>|<span class="hljs-string">     </span>|<span class="hljs-string">  ├─noDataTip
</span>|<span class="hljs-string">  </span>|<span class="hljs-string">   </span>|<span class="hljs-string">     </span>|<span class="hljs-string">  </span>|<span class="hljs-string">     └index.ejs
</span>|<span class="hljs-string">  </span>|<span class="hljs-string">   </span>|<span class="hljs-string">     </span>|<span class="hljs-string">  ├─nav
</span>|<span class="hljs-string">  </span>|<span class="hljs-string">   </span>|<span class="hljs-string">     </span>|<span class="hljs-string">  </span>|<span class="hljs-string">  ├─index.ejs
</span>|<span class="hljs-string">  </span>|<span class="hljs-string">   </span>|<span class="hljs-string">     </span>|<span class="hljs-string">  </span>|<span class="hljs-string">  └item.ejs
</span>|<span class="hljs-string">  </span>|<span class="hljs-string">   </span>|<span class="hljs-string">     </span>|<span class="hljs-string">  ├─courseList
</span>|<span class="hljs-string">  </span>|<span class="hljs-string">   </span>|<span class="hljs-string">     </span>|<span class="hljs-string">  </span>|<span class="hljs-string">     └index.ejs
</span>|<span class="hljs-string">  </span>|<span class="hljs-string">   </span>|<span class="hljs-string">     ├─index
</span>|<span class="hljs-string">  </span>|<span class="hljs-string">   </span>|<span class="hljs-string">     </span>|<span class="hljs-string">   ├─teacher
</span>|<span class="hljs-string">  </span>|<span class="hljs-string">   </span>|<span class="hljs-string">     </span>|<span class="hljs-string">   </span>|<span class="hljs-string">    ├─index.ejs
</span>|<span class="hljs-string">  </span>|<span class="hljs-string">   </span>|<span class="hljs-string">     </span>|<span class="hljs-string">   </span>|<span class="hljs-string">    └item.ejs
</span>|<span class="hljs-string">  </span>|<span class="hljs-string">   </span>|<span class="hljs-string">     </span>|<span class="hljs-string">   ├─student
</span>|<span class="hljs-string">  </span>|<span class="hljs-string">   </span>|<span class="hljs-string">     </span>|<span class="hljs-string">   </span>|<span class="hljs-string">    ├─index.ejs
</span>|<span class="hljs-string">  </span>|<span class="hljs-string">   </span>|<span class="hljs-string">     </span>|<span class="hljs-string">   </span>|<span class="hljs-string">    └item.ejs
</span>|<span class="hljs-string">  </span>|<span class="hljs-string">   </span>|<span class="hljs-string">     </span>|<span class="hljs-string">   ├─recomCourse
</span>|<span class="hljs-string">  </span>|<span class="hljs-string">   </span>|<span class="hljs-string">     </span>|<span class="hljs-string">   </span>|<span class="hljs-string">      ├─index.ejs
</span>|<span class="hljs-string">  </span>|<span class="hljs-string">   </span>|<span class="hljs-string">     </span>|<span class="hljs-string">   </span>|<span class="hljs-string">      └item.ejs
</span>|<span class="hljs-string">  </span>|<span class="hljs-string">   </span>|<span class="hljs-string">     </span>|<span class="hljs-string">   ├─collection
</span>|<span class="hljs-string">  </span>|<span class="hljs-string">   </span>|<span class="hljs-string">     </span>|<span class="hljs-string">   </span>|<span class="hljs-string">     ├─index.ejs
</span>|<span class="hljs-string">  </span>|<span class="hljs-string">   </span>|<span class="hljs-string">     </span>|<span class="hljs-string">   </span>|<span class="hljs-string">     └item.ejs
</span>|<span class="hljs-string">  </span>|<span class="hljs-string">   </span>|<span class="hljs-string">     </span>|<span class="hljs-string">   ├─carousel
</span>|<span class="hljs-string">  </span>|<span class="hljs-string">   </span>|<span class="hljs-string">     </span>|<span class="hljs-string">   </span>|<span class="hljs-string">    ├─director.ejs
</span>|<span class="hljs-string">  </span>|<span class="hljs-string">   </span>|<span class="hljs-string">     </span>|<span class="hljs-string">   </span>|<span class="hljs-string">    ├─index.ejs
</span>|<span class="hljs-string">  </span>|<span class="hljs-string">   </span>|<span class="hljs-string">     </span>|<span class="hljs-string">   </span>|<span class="hljs-string">    ├─indicator.ejs
</span>|<span class="hljs-string">  </span>|<span class="hljs-string">   </span>|<span class="hljs-string">     </span>|<span class="hljs-string">   </span>|<span class="hljs-string">    ├─item.ejs
</span>|<span class="hljs-string">  </span>|<span class="hljs-string">   </span>|<span class="hljs-string">     </span>|<span class="hljs-string">   </span>|<span class="hljs-string">    └slider.ejs
</span>|<span class="hljs-string">  </span>|<span class="hljs-string">   </span>|<span class="hljs-string">     ├─error
</span>|<span class="hljs-string">  </span>|<span class="hljs-string">   </span>|<span class="hljs-string">     </span>|<span class="hljs-string">   └index.ejs
</span>|<span class="hljs-string">  </span>|<span class="hljs-string">   </span>|<span class="hljs-string">     ├─common - 公共复用的文件
</span>|<span class="hljs-string">  </span>|<span class="hljs-string">   </span>|<span class="hljs-string">     </span>|<span class="hljs-string">   ├─mainTitle
</span>|<span class="hljs-string">  </span>|<span class="hljs-string">   </span>|<span class="hljs-string">     </span>|<span class="hljs-string">   </span>|<span class="hljs-string">     └index.ejs
</span>|<span class="hljs-string">  </span>|<span class="hljs-string">   </span>|<span class="hljs-string">     </span>|<span class="hljs-string">   ├─header
</span>|<span class="hljs-string">  </span>|<span class="hljs-string">   </span>|<span class="hljs-string">     </span>|<span class="hljs-string">   </span>|<span class="hljs-string">   ├─index.ejs
</span>|<span class="hljs-string">  </span>|<span class="hljs-string">   </span>|<span class="hljs-string">     </span>|<span class="hljs-string">   </span>|<span class="hljs-string">   ├─logo.ejs
</span>|<span class="hljs-string">  </span>|<span class="hljs-string">   </span>|<span class="hljs-string">     </span>|<span class="hljs-string">   </span>|<span class="hljs-string">   ├─nav.ejs
</span>|<span class="hljs-string">  </span>|<span class="hljs-string">   </span>|<span class="hljs-string">     </span>|<span class="hljs-string">   </span>|<span class="hljs-string">   └search.ejs
</span>|<span class="hljs-string">  </span>|<span class="hljs-string">   </span>|<span class="hljs-string">     </span>|<span class="hljs-string">   ├─footer
</span>|<span class="hljs-string">  </span>|<span class="hljs-string">   </span>|<span class="hljs-string">     </span>|<span class="hljs-string">   </span>|<span class="hljs-string">   ├─bottom.ejs
</span>|<span class="hljs-string">  </span>|<span class="hljs-string">   </span>|<span class="hljs-string">     </span>|<span class="hljs-string">   </span>|<span class="hljs-string">   ├─index.ejs
</span>|<span class="hljs-string">  </span>|<span class="hljs-string">   </span>|<span class="hljs-string">     </span>|<span class="hljs-string">   </span>|<span class="hljs-string">   └info.ejs
</span>|<span class="hljs-string">  </span>|<span class="hljs-string">   </span>|<span class="hljs-string">     </span>|<span class="hljs-string">   ├─courseItem
</span>|<span class="hljs-string">  </span>|<span class="hljs-string">   </span>|<span class="hljs-string">     </span>|<span class="hljs-string">   </span>|<span class="hljs-string">     └index.ejs
</span>|<span class="hljs-string">  </span>|<span class="hljs-string">   ├─layout - 布局复用的文件
</span>|<span class="hljs-string">  </span>|<span class="hljs-string">   </span>|<span class="hljs-string">   ├─foot.ejs
</span>|<span class="hljs-string">  </span>|<span class="hljs-string">   </span>|<span class="hljs-string">   └head.ejs
</span>|<span class="hljs-string">  </span>|<span class="hljs-string">   ├─datas - 隐藏的div保存字符串数据显示在html dom节点
</span>|<span class="hljs-string">  </span>|<span class="hljs-string">   </span>|<span class="hljs-string">   └courseData.ejs
</span>|<span class="hljs-string">  ├─utils
</span>|<span class="hljs-string">  </span>|<span class="hljs-string">   └tools.js - 前端工具/模板解析/数据筛选/去空格
</span>|<span class="hljs-string">  ├─templates
</span>|<span class="hljs-string">  </span>|<span class="hljs-string">     └courseItem.tpl - 用于列表页navpage页渲染模板
</span>|<span class="hljs-string">  ├─styles
</span>|<span class="hljs-string">  </span>|<span class="hljs-string">   ├─carousel.scss
</span>|<span class="hljs-string">  </span>|<span class="hljs-string">   ├─collection.scss
</span>|<span class="hljs-string">  </span>|<span class="hljs-string">   ├─common.css
</span>|<span class="hljs-string">  </span>|<span class="hljs-string">   ├─courseItem.scss
</span>|<span class="hljs-string">  </span>|<span class="hljs-string">   ├─courseList.scss
</span>|<span class="hljs-string">  </span>|<span class="hljs-string">   ├─courseNav.scss
</span>|<span class="hljs-string">  </span>|<span class="hljs-string">   ├─error.scss
</span>|<span class="hljs-string">  </span>|<span class="hljs-string">   ├─footer.scss
</span>|<span class="hljs-string">  </span>|<span class="hljs-string">   ├─header.scss
</span>|<span class="hljs-string">  </span>|<span class="hljs-string">   ├─iconfont.css
</span>|<span class="hljs-string">  </span>|<span class="hljs-string">   ├─mainTitle.scss
</span>|<span class="hljs-string">  </span>|<span class="hljs-string">   ├─noDataTip.scss
</span>|<span class="hljs-string">  </span>|<span class="hljs-string">   ├─recomCourse.scss
</span>|<span class="hljs-string">  </span>|<span class="hljs-string">   ├─resets.css
</span>|<span class="hljs-string">  </span>|<span class="hljs-string">   ├─teacher.scss
</span>|<span class="hljs-string">  </span>|<span class="hljs-string">   ├─ui.scss
</span>|<span class="hljs-string">  </span>|<span class="hljs-string">   ├─variable.scss
</span>|<span class="hljs-string">  </span>|<span class="hljs-string">   ├─fonts
</span>|<span class="hljs-string">  </span>|<span class="hljs-string">   </span>|<span class="hljs-string">   ├─iconfont.eot
</span>|<span class="hljs-string">  </span>|<span class="hljs-string">   </span>|<span class="hljs-string">   ├─iconfont.svg
</span>|<span class="hljs-string">  </span>|<span class="hljs-string">   </span>|<span class="hljs-string">   ├─iconfont.ttf
</span>|<span class="hljs-string">  </span>|<span class="hljs-string">   </span>|<span class="hljs-string">   ├─iconfont.woff
</span>|<span class="hljs-string">  </span>|<span class="hljs-string">   </span>|<span class="hljs-string">   └iconfont.woff2
</span>|<span class="hljs-string">  ├─modules - 逻辑功能模块
</span>|<span class="hljs-string">  </span>|<span class="hljs-string">    ├─Carousel.js - 轮播图
</span>|<span class="hljs-string">  </span>|<span class="hljs-string">    ├─CourseNav.js - 导航栏
</span>|<span class="hljs-string">  </span>|<span class="hljs-string">    └HeaderSearch.js - 搜索栏
</span>|<span class="hljs-string">  ├─js - 入口文件/引入网页样式文件和逻辑功能模块
</span>|<span class="hljs-string">  </span>|<span class="hljs-string"> ├─error.js
</span>|<span class="hljs-string">  </span>|<span class="hljs-string"> ├─index.js
</span>|<span class="hljs-string">  </span>|<span class="hljs-string"> └list.js
</span>|<span class="hljs-string">  ├─img
</span>|<span class="hljs-string">  </span>|<span class="hljs-string">  └logo.png
</span>|<span class="hljs-string">  ├─config - 前端配置信息
</span>|<span class="hljs-string">  </span>|<span class="hljs-string">   └config.js - 轮播图/域名配置
├─services - 后端操作数据库的服务
</span>|<span class="hljs-string">    ├─Collection.js
</span>|<span class="hljs-string">    ├─Course.js
</span>|<span class="hljs-string">    ├─CourseTab.js
</span>|<span class="hljs-string">    ├─RecomCourse.js
</span>|<span class="hljs-string">    ├─Slider.js
</span>|<span class="hljs-string">    ├─Student.js
</span>|<span class="hljs-string">    └Teacher.js
├─routes - 路由管理
</span>|<span class="hljs-string">   └index.js
├─public - 静态资源
</span>|<span class="hljs-string">   ├─js
</span>|<span class="hljs-string">   </span>|<span class="hljs-string"> ├─error.js
</span>|<span class="hljs-string">   </span>|<span class="hljs-string"> ├─index.js
</span>|<span class="hljs-string">   </span>|<span class="hljs-string"> ├─list.js
</span>|<span class="hljs-string">   </span>|<span class="hljs-string"> └main.js
</span>|<span class="hljs-string">   ├─img
</span>|<span class="hljs-string">   </span>|<span class="hljs-string">  ├─logo-c872049b5cd29849.png
</span>|<span class="hljs-string">   </span>|<span class="hljs-string">  └logo108.png
</span>|<span class="hljs-string">   ├─css
</span>|<span class="hljs-string">   </span>|<span class="hljs-string">  ├─error.css
</span>|<span class="hljs-string">   </span>|<span class="hljs-string">  ├─index.css
</span>|<span class="hljs-string">   </span>|<span class="hljs-string">  └list.css
├─libs - 后端工具
</span>|<span class="hljs-string">  └utils.js - 搜索筛选
├─db - 数据库
</span>|<span class="hljs-string"> ├─db_connect.js - 连接数据库
</span>|<span class="hljs-string"> ├─models - 表模型
</span>|<span class="hljs-string"> </span>|<span class="hljs-string">   ├─aboutus.js
</span>|<span class="hljs-string"> </span>|<span class="hljs-string">   ├─agencyInfo.js
</span>|<span class="hljs-string"> </span>|<span class="hljs-string">   ├─collection.js
</span>|<span class="hljs-string"> </span>|<span class="hljs-string">   ├─course.js
</span>|<span class="hljs-string"> </span>|<span class="hljs-string">   ├─courseTab.js
</span>|<span class="hljs-string"> </span>|<span class="hljs-string">   ├─recomCourse.js
</span>|<span class="hljs-string"> </span>|<span class="hljs-string">   ├─slider.js
</span>|<span class="hljs-string"> </span>|<span class="hljs-string">   ├─student.js
</span>|<span class="hljs-string"> </span>|<span class="hljs-string">   └teacher.js
├─controllers - 控制器
</span>|<span class="hljs-string">      └Home.js - 关联路由/对响应首页/列表页/错误页的管理和传值
├─configs - 后端配置信息
</span>|<span class="hljs-string">    ├─db.js - 启动服务器配置
</span>|<span class="hljs-string">    ├─db_type.js - 数据库表字段
</span>|<span class="hljs-string">    ├─env.js - 环境
</span>|<span class="hljs-string">    ├─link.js - 首页底栏合作平台链接信息
</span>|<span class="hljs-string">    ├─manual.js - 首页底栏官方手册集合信息(基于一张雪碧图)
</span>|<span class="hljs-string">    ├─nav.js - 首页顶部nav栏信息
</span>|<span class="hljs-string">    ├─page.js - head标签配置信息
</span>|<span class="hljs-string">    ├─qr.js - 底部二维码信息
</span>|<span class="hljs-string">    └url.js - 域名地址
├─bin
</span>|<span class="hljs-string">  └www</span></code></pre>
<p><strong>项目地址：</strong> <a href="https://gitee.com/kevinleeeee/crawler-txcourse-website-demo">https://gitee.com/kevinleeeee/crawler-txcourse-website-demo</a></p>
<p>​</p>

  </div>
</body>

</html>